package com.lsc.record.core.service.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import com.alibaba.fastjson2.JSONArray;
import com.lsc.record.controller.parameter.PageInfo;
import com.lsc.record.controller.parameter.Parameter;
import com.lsc.record.core.entity.DmContent;
import com.lsc.record.core.entity.DmType;
import com.lsc.record.core.entity.DmTypeAttr;
import com.lsc.record.core.mapper.DmContentMapper;
import com.lsc.record.core.service.ContentServcie;
import com.lsc.record.core.service.DocumentServcie;
import com.lsc.record.core.service.TypeService;
import com.lsc.record.core.util.RowConvertUtil;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.Db;
import com.mybatisflex.core.row.Row;

import cn.hutool.core.util.IdUtil;



@Service
public class DocumentServiceImpl implements DocumentServcie {
	
	@Resource
    private TypeService typeService;
	
	@Resource
	private DmContentMapper contentMapper;
	
	@Resource
	private ContentServcie contentServcie;
	
	
	@Override
	public Page<Row> queryPage(PageInfo pageInfo, String typeName,JSONArray parameters) {
		
        DmType type = typeService.getByTypeName(typeName);
        String[] columns = typeService.getTypeQueryColumn(type.getId()).split(",");
        Page<Row> page = Page.of(pageInfo.getPageIndex(),pageInfo.getPageSize());
        QueryWrapper queryWrapper = getBaseQueryWrapper(parameters,columns);
        
        List<Row> list =RowConvertUtil.toRowListLowerKey(page.getRecords());
        page.setRecords(list);
        return Db.paginate(type.getTableName(), page, queryWrapper);
	}
	
	
	private QueryWrapper getBaseQueryWrapper(JSONArray parameters, String[] columns) {
		QueryWrapper queryWrapper = QueryWrapper.create();
		if (parameters != null && !parameters.isEmpty()) {
			for (int i = 0; i < parameters.size(); i++) {
				Parameter param = parameters.getJSONObject(i).to(Parameter.class);
				String queryKey = param.getKey();
				switch (param.getType()) {
				case "like":
					queryWrapper.like(queryKey, param.getValue());
					break;
				case "in":
					String[] values = param.getValue().split(",");
					Set<String> setValue = new HashSet<>(Arrays.asList(values));
					queryWrapper.in(queryKey, setValue);
					break;
				case "eq":
					queryWrapper.eq(queryKey, param.getValue());
					break;
				case "between":
					String[] btValue = param.getValue().split(",");
					boolean isDatetime = queryKey.toLowerCase().endsWith("_time")
							|| queryKey.toLowerCase().endsWith("_date");
					if (isDatetime && btValue[0].length() <= 10) {
						queryWrapper.between(queryKey, btValue[0] + " 00:00:00", btValue[1] + " 23:59:59");
					} else {
						queryWrapper.between(queryKey, btValue[0], btValue[1]);
					}
					break;
				default:
					queryWrapper.eq(param.getKey(), param.getValue());
					break;
				}
			}
		}
		if(columns!=null && columns.length>0) {			
			queryWrapper.select(columns);
		}
		return queryWrapper;

	}

	
	@Override
	public Row create(String typeName, Map<String, Object> data) throws Exception {
		DmType type = typeService.getByTypeName(typeName);
		if(type==null) {
			throw new Exception("类型["+typeName+"] 不存在");
		}
		
		checkTableFields(type,data);
		
		String id = type.getSnCode()+IdUtil.getSnowflakeNextIdStr();
		Row row = new Row();
		row.putAll(data);
		row.set("id", id);
		row.set("type_name", type.getName());
		
		//必填项检查
		checkRequired(type,data);
		//唯一项检查
		checkUniqueness(type,data);
		
		Db.insert(type.getTableName(), row);
		row = RowConvertUtil.toRowLowerKey(row);
	    return row;
	}
	
	
	@Override
	public Row create(String typeName, Map<String, Object> data, MultipartFile file) throws Exception {
		String formatName = getFileExtension(file);
		data.put("format_name", formatName);
		Row docObj = this.create(typeName, data);
		DmType type = typeService.getByTypeName(typeName);
		docObj.put("id", type.getId());
		
		DmContent content = new DmContent();
		content.setName(docObj.getString("name"));
		content.setStoreId(type.getStoreId());
		content.setFormatName(formatName);
		content.setDocId(docObj.getString("id"));
		content.setInputStream(file.getInputStream());
		contentServcie.create(content, "");
		docObj = RowConvertUtil.toRowLowerKey(docObj);
		return docObj;
	}
	
	private String getFileExtension(MultipartFile multipartFile) {
	    String originalFilename = multipartFile.getOriginalFilename();
	    int extensionIndex = originalFilename.lastIndexOf(".");
	    if (extensionIndex != -1) {
	        return originalFilename.substring(extensionIndex + 1);
	    } else {
	        return "";
	    }
	}
	
	/**
	 * 
	 * @param tableName
	 * @param folderId
	 * @param isDeepin 是否深度查询
	 * @return
	 */
	private List<Row> getDocumentsInFolder(String tableName,String folderId,boolean isDeepin){
    	String columns="ID";
    	String scolumns="c."+ columns.replace(",", ",c.");
    	
    	System.out.println(columns);
    	StringBuffer sqlBuilder = null;
    	if(isDeepin) {    		
    		sqlBuilder = new StringBuffer("with recursive dmi_folder ("+columns+") as (");
    		sqlBuilder.append("select "+columns+" from dm_folder where parent_id='"+folderId+"'");
    		sqlBuilder.append(" union all ");
    		sqlBuilder.append("select "+scolumns+" from dm_folder as c join dmi_folder p on c.parent_id=p.id");
    		sqlBuilder.append(")");
    		sqlBuilder.append("select * from dmi_folder");
    	}else {
    		sqlBuilder = new StringBuffer("'"+folderId+"'");
    	}
    	
    	String sql = "select * from "+tableName +" where folder_id in ("+sqlBuilder.toString()+")";
    	List<Row> folderlist = Db.selectListBySql(sql);
    	return folderlist;
    }
	
	/**
	 * 字段有效性检查
	 * @throws Exception 
	 */
	private void checkTableFields(DmType type,Map<String,Object> data) throws Exception {
		String[] columns = typeService.getTypeQueryColumn(type.getId()).split(",");
	    Set<String> columnSet = new HashSet<>();
	    for (String name : columns) {
	    	columnSet.add(name);
		}
		Set<String> keys = data.keySet();
	    StringBuffer sb = new StringBuffer();
		for (Iterator<String> iterator = keys.iterator(); iterator.hasNext();) {
			String key = iterator.next().toLowerCase();
			if(!columnSet.contains(key)) {
				if(sb.length()>0) {
					sb.append(",");
				}
				sb.append(key);
			}
		}
		
		if(sb.length()>0) {
			throw new Exception("类型["+type.getName()+"],没有以下字段："+sb.toString());
		}
	}
	
	/**
	 * 检查必填项
	 * @param type
	 * @param data
	 * @throws Exception
	 */
	private void checkRequired(DmType type,Map<String,Object> data) throws Exception {
		String typeName = type.getName();
		List<DmTypeAttr> reqAttrs = getRequitedAttr(type);
		if(reqAttrs!=null && reqAttrs.size()>0) {
			for (DmTypeAttr attr : reqAttrs) {
				String field = attr.getName().toLowerCase();
				if(field.equals("id")) {
					continue;
				}
				if(!data.containsKey(field)) {
					throw new Exception("类型["+typeName+"],必填属性【"+field+"】未填写");
				}
			}
		}
	}
	
	/**
	 * 获取必填属性列
	 * @param type
	 * @return
	 */
	private List<DmTypeAttr> getRequitedAttr(DmType type){
		List<DmTypeAttr> list = new ArrayList<>();
		List<DmTypeAttr> attrs = type.getItems();
		for (DmTypeAttr attrObj : attrs) {
			if(!attrObj.getDataNullable()) {
				list.add(attrObj);
			}
		}
		return list;
	}
	
	/**
	 * 获取唯一性属性列
	 * @param type
	 * @return
	 */
	private List<DmTypeAttr> getUniquenessAttr(DmType type){
		List<DmTypeAttr> list = new ArrayList<>();
		List<DmTypeAttr> attrs = type.getItems();
		for (DmTypeAttr attrObj : attrs) {
			if(attrObj.getUniqueness() && !attrObj.getName().toLowerCase().equals("id")) {
				list.add(attrObj);
			}
		}
		return list;
	}
	
	private void checkUniqueness(DmType type,Map<String,Object> data) throws Exception {
		List<DmTypeAttr> unAttrs = getUniquenessAttr(type);
		if(unAttrs!=null && unAttrs.size()>0) {
			for (DmTypeAttr attr : unAttrs) {
				String field = attr.getName().toLowerCase();
				if(data.containsKey(field)) {
					String value = data.get(field).toString();
					checkUniquenessItem(type.getName(),type.getTableName(),attr.getName(),value);
				}
			}
		}
	}
	
	private void checkUniquenessItem(String typeName,String tableName,String fieldName,String value) throws Exception {
		String sql = "select * from "+tableName+" where (type_name=? or type_name=?) and "+fieldName+" = ?";
		List<Row> list = Db.selectListBySql(sql, typeName.toUpperCase(),typeName.toLowerCase(),value);
		if(list!=null && list.size()>0) {
			throw new Exception("类型["+typeName+"],唯一性属性【"+fieldName+"】字段值【"+value+"】已存在");
		}
	}


	@Override
	public DmContent getCurrentContent(String docId) throws Exception {
		QueryWrapper queryWrapper = QueryWrapper.create().eq("doc_id", "1");
    	queryWrapper.orderBy("content_primary_version", false);
    	queryWrapper.orderBy("content_sub_version",false);    	
    	DmContent obj = contentMapper.selectOneWithRelationsByQuery(queryWrapper);
		return obj;
	}


	@Override
	public List<DmContent> getContentVersionList(String docId) throws Exception {
		QueryWrapper queryWrapper = QueryWrapper.create().eq("doc_id", docId);
    	queryWrapper.orderBy("content_primary_version", false);
    	queryWrapper.orderBy("content_sub_version",false);    	
    	List<DmContent> list = contentMapper.selectListWithRelationsByQuery(queryWrapper);
    	return list;
	}


	/**
	 *
	 */
	@Override
	public Row getDocument(String id) {
		Row row= Db.selectOneById("DM_DOCUMENT_VIEW", Row.of("id", id));
		row = RowConvertUtil.toRowLowerKey(row);
		
		String typeName = row.getString("type_name");
		String tableName = row.getString("table_name");
		
		DmType type = typeService.getByTypeName(typeName);
		StringBuffer columns = new StringBuffer();
		for (DmTypeAttr attr : type.getItems()) {
			if(columns.length()>0) {
				columns.append(",");
			}
			columns.append(attr.getName());
		}
		
		String docSql = "select "+columns.toString()+" from "+tableName +" where id=?";
		row = Db.selectOneBySql(docSql, id);
		row = RowConvertUtil.toRowLowerKey(row);
		return row;
	}


	@Override
	public Boolean update(Map<String, Object> data) throws Exception {
		Row row = new Row();
		row.putAll(data);
		if(!row.containsKey("id")) {
			throw new Exception("未传递ID");
		}
		String id = row.getString("id");
		if(!row.containsKey("type_name")) {
			throw new Exception("未传递type_name");
		}
		
		Row docObj = this.getDocument(id);
		Set<String> keys = row.keySet();
		StringBuffer errorKeys = new StringBuffer();
		for (String key : keys) {
			if(!docObj.containsKey(key)) {
				if(errorKeys.length()>0) {
					errorKeys.append(",");
				}
				errorKeys.append(key);
			}
		}
		if(errorKeys.length()>0) {
			throw new Exception("字段 "+errorKeys.toString() +" 不存在");
		}
		String typeName = row.getString("type_name");
		DmType type = typeService.getByTypeName(typeName);
		int updateResult = Db.updateById(type.getTableName(), row);
		return updateResult>0;
	}




}
